package com.soul.server.server;

import com.alibaba.fastjson.JSON;
import com.soul.autoconfig.template.OssTemplate;
import com.soul.commons.constans.Constants;
import com.soul.commons.exception.SoulGlobalException;
import com.soul.dubbo.api.db.UserInfoApi;
import com.soul.dubbo.api.mongo.CommentApi;
import com.soul.dubbo.api.mongo.MovementApi;
import com.soul.dubbo.api.mongo.VisitorApi;
import com.soul.model.db.User;
import com.soul.model.db.UserInfo;
import com.soul.model.eums.CommentType;
import com.soul.model.mongo.Comment;
import com.soul.model.mongo.Movement;
import com.soul.model.mongo.Visitors;
import com.soul.model.vo.*;
import com.soul.server.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author mdoya
 * @version 1.0
 * @description: 圈子业务层
 */
@Slf4j
@Service
public class MovementService {

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private MovementApi movementApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private CommentApi commentApi;

    @DubboReference
    private VisitorApi visitorApi;

    @Autowired
    private MqMessageService mqMessageService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     *  圈子-用户发布动态
     * @param movementVo 参数
     * @param imageContent 图片数组
     * @return null
     */
    public void addMovements(MovementVo movementVo, MultipartFile[] imageContent) {

        try {
            Long userId = UserHolder.getUserId();
            ArrayList<String> list = new ArrayList<>();
            // 1. 上传图片到OSS服务器
            if (imageContent != null){
                for (MultipartFile multipartFile : imageContent) {
                    // String originalFilename = multipartFile.getOriginalFilename(); // 原来图片名称
//                    String upload = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
                    list.add(ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream()));
                }
            }
            // 2. 保存用户发布动态
            Movement movement = new Movement();
            BeanUtils.copyProperties(movementVo,movement); // 可以拷贝字段 textContent  longitude  latitude
            movement.setUserId(userId);
            movement.setLocationName(movementVo.getLocation());
            movement.setMedias(list);
            // 3. 用户操作log日志记录
            String movementId = movementApi.addMovements(movement);
            mqMessageService.sendLogMessage(userId,"0201","movement",movementId);
            // 发布动态审核  rabbitmq异步处理
            mqMessageService.sendAudiMessage(movementId);
        } catch (IOException e) {
            log.error("圈子-用户发布动态异常: {}",e.getMessage());
            throw new SoulGlobalException(ErrorResult.error());
        }

    }

    public PageResult<MovementsVo> findPageMovement(Long page, Long pageSize, Long userId) {
    // 1 根据用户id分页查询动态数据（Movement）
        PageResult<Movement> movementPageResult = movementApi.findPageMovement(page, pageSize, userId);
        if(CollectionUtils.isEmpty(movementPageResult.getItems())){
//            return null; // 这样有可能有问题
            return new PageResult<>();
        }
        //2根据用户id查询用户信息 tb_user_info表
        UserInfo userInfo = userInfoApi.findByUserIdUser(userId);
        //3循环遍历动态数据 基于动态数据与用户信息构造Vo返回
        List<MovementsVo> movementsVoList = new ArrayList<>();
        for (Movement movement : movementPageResult.getItems()) {
            movementsVoList.add(MovementsVo.init(userInfo,movement));
        }
        return new PageResult<>(page,pageSize,movementPageResult.getCounts(),movementsVoList);
    }

    /**
     *  圈子 - 好友动态
     * @param page 每个码数
     * @param pagesize 每页条数
     * @return ResponseEntity
     */
    public PageResult<MovementsVo> findFriendPageMovements(Long page, Long pagesize) {
        Long userId = UserHolder.getUserId();
        // 1. 拿到当前登录所有好友动态
        PageResult<Movement> movementPageResult = movementApi.findFriendPageMovements(page,pagesize,userId);
        if (CollectionUtils.isEmpty(movementPageResult.getItems())){
            return null;
        }

        List<Movement> movementList = movementPageResult.getItems();
        // 2. 拿到所有好友动态id
        List<Long> userIdsList = movementList.stream().map(Movement::getUserId).collect(Collectors.toList());

        // 3. 根据动态id找到对应发布动态作者详细信息
        Map<Long,UserInfo> userInfoMap = userInfoApi.findByIds(userIdsList);

        // 4. 根据动态id动态找到对应的发布作者信息封装
        List<MovementsVo> movementsVoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(movementList)){
            for (Movement movement : movementList) {
                UserInfo userInfo = userInfoMap.get(movement.getUserId());
                movementsVoList.add(MovementsVo.init(userInfo,movement));
            }
        }
        // 5. 封装返回给前端
        return new PageResult<>(page,pagesize,movementPageResult.getCounts(),movementsVoList);
    }

    /**
     *  圈子 - 推荐好友
     * @param page 每个码数
     * @param pagesize 每页条数
     * @return ResponseEntity
     */
    public PageResult<MovementsVo> findRecommendPageMovements(Long page, Long pagesize) {
        Long currendUserId = UserHolder.getUserId();
        // 大数据推荐动态
        String key = Constants.MOVEMENTS_RECOMMEND + currendUserId; // 别人定好redis中key
        String pids = stringRedisTemplate.opsForValue().get(key);

        List<Movement> movementList = new ArrayList<>();
        long count = 0l;
        if (StringUtils.isEmpty(pids)){
           movementList = movementApi.randomMovement(page,pagesize,currendUserId);
        } else {
            String[] redisUserIds = pids.split(",");
            Long startIndex = (page - 1) * pagesize;
            if (startIndex < redisUserIds.length){
                List<Long> userIds = Arrays.stream(redisUserIds).skip(startIndex).limit(pagesize).map(Long::valueOf).collect(Collectors.toList());
                movementList = movementApi.findByIds(userIds);
            }
            count = redisUserIds.length;
        }

        // 1. 查询所有好友动态，根据匹配度推荐

        // 2. 拿到所有动态用户ids
        List<Long> mevementIds = movementList.stream().map(Movement::getUserId).collect(Collectors.toList());
        Map<Long, UserInfo> userInfoMap = userInfoApi.findByIds(mevementIds);
        // 3. 构造数据
        List<MovementsVo> movementsVoList = new ArrayList<>();
        for (Movement movement : movementList) {
            if (userInfoMap != null){
                UserInfo userInfo = userInfoMap.get(movement.getUserId());
                if (userInfo != null){
                    MovementsVo vo = MovementsVo.init(userInfo, movement);
                    String typeKey = Constants.MOVEMENT_LIKE_HASHKEY + movement.getId().toHexString();
                    String businessTypeKey  = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
                    // 动态点赞设置
                    if (!StringUtils.isEmpty(stringRedisTemplate.opsForHash().get(typeKey, businessTypeKey))){
                        vo.setHasLiked(1); // 已经点赞
                    }
                    // 动态喜欢设置
                    String loveKey = Constants.MOVEMENT_LOVE_HASHKEY+ movement.getId().toHexString();
                    String lovehashKey = Constants.MOVEMENT_LOVE_HASHKEY + currendUserId;
                    if (!StringUtils.isEmpty(stringRedisTemplate.opsForHash().get(loveKey,lovehashKey))){
                        vo.setHasLoved(1); // 已经喜欢
                    }
                    movementsVoList.add(vo);
                }
            }
        }

        //  封装数据返回前端
        return new PageResult<>(page,pagesize,Long.valueOf(mevementIds.size()),movementsVoList);
    }

    /**
     *  圈子 - 动态点赞
     * @param likeId 点赞标识
     * @return
     */
    public Integer like(String likeId) {
        Long currendUserId = UserHolder.getUserId();
        mqMessageService.sendLogMessage(currendUserId,"0203","movement",likeId);
        String key = Constants.FREEZE_USER + currendUserId;
        if (org.apache.commons.lang.StringUtils.isNotEmpty(stringRedisTemplate.opsForValue().get(key))){
            String redisStr = stringRedisTemplate.opsForValue().get(key);
            Map<String,String> map = JSON.parseObject(redisStr, Map.class);
            String userId = map.get("userId"); // 被冻结用户id
            String freezingTime = map.get("freezingTime"); // 冻结时间，1为冻结3天，2为冻结7天，3为永久冻结
            String freezingRange = map.get("freezingRange"); // 冻结范围，1为冻结登录，2为冻结发言，3为冻结发布动态
            String reasonsForFreezing = map.get("reasonsForFreezing"); // 冻结原因
            String frozenRemarks = map.get("frozenRemarks"); // 冻结备注
            throw new SoulGlobalException("因您"+reasonsForFreezing+ "账号被冻结" +freezingTime);
        }
        // 1. 查询当前用户点赞
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(likeId));
        comment.setUserId(currendUserId);
        comment.setCommentType(CommentType.LIKE.getType());
        Integer count = commentApi.addComment(comment);
        // 2. redis计数点赞条数
        String typeKey = Constants.MOVEMENT_LIKE_HASHKEY + likeId;
        String businessTypeKey  = Constants.MOVEMENT_LIKE_HASHKEY + currendUserId;
        stringRedisTemplate.opsForHash().put(typeKey,businessTypeKey,"1");
        return count;
    }

    /**
     *  圈子 - 动态取消点赞
     * @param likeId 取消点赞
     * @return
     */
    public Integer dislike(String likeId) {
        User user = UserHolder.getUser();
        Long currendUserId = user.getId();
        // 1. 查询当前用户点赞
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(likeId));
        comment.setUserId(currendUserId);
        comment.setCommentType(CommentType.LIKE.getType());
        Integer count = commentApi.deleteComment(comment);
        // 2. redis计数点赞条数
        String typeKey = Constants.MOVEMENT_LIKE_HASHKEY + likeId;
        String businessTypeKey  = Constants.MOVEMENT_LIKE_HASHKEY + currendUserId;
        stringRedisTemplate.opsForHash().delete(typeKey,businessTypeKey);
        return count;
    }

    /**
     *  圈子 - 单挑动态
     * @param movementId 动态id
     * @return MovementsVo
     */
    public MovementsVo findByMovement(String movementId) {
        // 1. 根据动态id拿到详细动态信息
        Movement movement = movementApi.findById(movementId);
        // 2. 获取动态发布者用户详细信息
        UserInfo userInfo = userInfoApi.findByUserIdUser(movement.getUserId());
        // 3. 构造vo参数对象
        return MovementsVo.init(userInfo,movement);
    }

    /**
     *  圈子 - 动态喜欢
     * @param loveId 标识
     * @return 总条数
     */
    public Integer love(String loveId) {
        // 1. 构建Comment集合参数新增
        Long currendUserId = UserHolder.getUserId();
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(loveId));
        comment.setCommentType(CommentType.LOVE.getType());
        comment.setUserId(currendUserId);
        // 1.2 返回喜欢总条数
        Integer count = commentApi.addComment(comment);
        // 2. 喜欢保存到redis中
        String loveKey = Constants.MOVEMENT_LOVE_HASHKEY+ loveId;
        String loveHashKey = Constants.MOVEMENT_LOVE_HASHKEY + currendUserId;
        stringRedisTemplate.opsForHash().put(loveKey,loveHashKey,"1");
        return count;
    }

    /**
     *  圈子 - 动态不喜欢
     * @param loveId 标识
     * @return 总条数
     */
    public Integer unlove(String loveId) {
        // 1. 构建Comment集合参数新增
        Long currendUserId = UserHolder.getUserId();
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(loveId));
        comment.setCommentType(CommentType.LOVE.getType());
        comment.setUserId(currendUserId);
        // 1.2 返回喜欢总条数
        Integer count = commentApi.deleteComment(comment);
        // 2. 喜欢保存到redis中
        String loveKey = Constants.MOVEMENT_LOVE_HASHKEY+ loveId;
        String loveHashKey = Constants.MOVEMENT_LOVE_HASHKEY + currendUserId;
        stringRedisTemplate.opsForHash().delete(loveKey,loveHashKey);
        return count;
    }

    /**
     *  首页 - 谁看过我
     * @return List<VisitorsVo>
     */
    public List<VisitorsVo> findVisitors() {
        Long currendUserId = UserHolder.getUserId();
        // 1. redis的key, hash 所有用户的访客时间都记录这个hash集合里
        String key = Constants.VISITORS_USER;
        // 2. whoKey,登录用户id
        String whoKey = currendUserId.toString();
        // 3.根据登录用户id查询redis访客记录
        String lastTimeStr = (String) stringRedisTemplate.opsForHash().get(key, whoKey);

        // 时间戳字符串转成long类型，visitor集合中的date是long类型 2022-02-11 12:00:00
        Long lastTime = lastTimeStr==null?null:Long.valueOf(lastTimeStr);

        // 4. 查询visitors集合所有访问我的记录
        List<Visitors> visitorsList = visitorApi.findVisitors(currendUserId,lastTime);
        // 5. 用户被访问过
        List<VisitorsVo> visitorsVoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(visitorsList)){
            // 6. 所有来访者ids  拿到来访者用户详细信息
            List<Long> visitorsIds = visitorsList.stream().map(Visitors::getVisitorUserId).collect(Collectors.toList());
            Map<Long, UserInfo> userInfoMap = userInfoApi.findIdsUserInfoList(visitorsIds);
            // 7. 构造数据
            for (Visitors visitors : visitorsList) {
                if (userInfoMap != null){
                    UserInfo userInfo = userInfoMap.get(visitors.getVisitorUserId());
                    if (userInfo != null){
                        visitorsVoList.add(VisitorsVo.init(userInfo,visitors));

                    }
                }
            }
        }

        // 8. 返回
        return visitorsVoList;
    }
}
